﻿using OnlineEducation.Areas.Controllers;
using OnlineEducation.Data;
using OnlineEducation.Data.Entities;
using OnlineEducation.Extensions;
using OnlineEducation.Models.AccountViewModels;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using System;
using System.Collections;
using System.Threading.Tasks;

namespace OnlineEducation.Controllers
{
    [Authorize]
    public class AccountController : BaseController
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signInManager;
        private readonly ILogger _logger;
        private readonly ApplicationDbContext _context;
        private readonly IDistributedCache _distributedCache;
  
        private readonly string REG_KEY = "__register__";
        private readonly string RESET_PWD = "__resetpassword__";
  
        public AccountController(
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager,
            ILogger<AccountController> logger,
            IDistributedCache distributedCache,
            ApplicationDbContext context)
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _logger = logger;
            _distributedCache = distributedCache;
            _context = context;

        }

        [TempData]
        public string ErrorMessage { get; set; }


        /// <summary>
        /// 展示用户登录界面
        /// </summary>
        /// <param name="returnUrl"></param>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> Login(string returnUrl = null)
        {
            // Clear the existing external cookie to ensure a clean login process
            await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);

            ViewData["ReturnUrl"] = returnUrl;
            return View();
        }
        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="model"></param>
        /// <param name="returnUrl"></param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
        {
            ViewData["ReturnUrl"] = returnUrl;
            if (ModelState.IsValid)
            {
                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, set lockoutOnFailure: true
                var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: true);
                if (result.Succeeded)
                {
                    _logger.LogInformation("User logged in.");

                    return RedirectToLocal(returnUrl);
                }

                if (result.IsLockedOut)
                {
                    _logger.LogWarning("User account locked out.");
                    return RedirectToAction(nameof(Lockout));
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "用户名或者密码错误.");
                    ViewData["error"] = "用户名或者密码错误.";
                    return View(model);
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        /// <summary>
        /// 展示锁定界面
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public IActionResult Lockout()
        {
            return View();
        }
        /// <summary>
        /// 展示注册成功界面
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public IActionResult RegisterSuccess()
        {
            return View();
        }
        /// <summary>
        /// 展示注册界面
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="returnUrl"></param>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public IActionResult Register(string userid = null, string returnUrl = null)
        {
            ViewData["ReturnUrl"] = returnUrl;
            ViewBag.IntroducerUserID = userid;
            return View();
        }
        /// <summary>
        /// 注册用户，验证保存在redis的验证码是否正确。
        /// </summary>
        /// <param name="model"></param>
        /// <param name="returnUrl"></param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
        {
            ViewData["ReturnUrl"] = returnUrl;

            if (ModelState.IsValid)
            {
                string key = REG_KEY + model.UserName;

                var randomCode = _distributedCache.GetString(key);

                if (randomCode == null)
                {
                    ModelState.AddModelError("ValidationCode", "验证码已过期");
                }
                else if (randomCode != model.ValidationCode)
                {
                    ModelState.AddModelError("ValidationCode", "验证码错误");
                }
                else
                {

                    var user = new ApplicationUser { UserName = model.UserName, Email = model.UserName, CreatedTime = DateTime.Now };

                    //user registered using registration screen is SuperAdmin

                    var result = await _userManager.CreateAsync(user, model.Password);

                    if (model.UserType == "1")
                    {
                        await _userManager.AddToRoleAsync(user, "Teacher");
                    }
                    else
                    {
                        await _userManager.AddToRoleAsync(user, "Student");
                    }
                 

                    if (result.Succeeded)
                    {
                        _logger.LogInformation("User created a new account with password.");

                        var loginresult = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, true, lockoutOnFailure: true);
                        if (loginresult.Succeeded)
                        {
                            _logger.LogInformation("User logged in.");

                            return RedirectToAction(nameof(HomeController.Index), "Home");

                        }
                    }
                    AddErrors(result);
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        /// <summary>
        /// 注销
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Logout()
        {
            await _signInManager.SignOutAsync();

            HttpContext.Session.Clear();

            _logger.LogInformation("User logged out.");

            return RedirectToAction(nameof(HomeController.Index), "Home");
        }

        /// <summary>
        /// 展示重设密码界面
        /// </summary>
        /// <returns></returns>

        [HttpGet]
        [AllowAnonymous]
        public IActionResult ResetPassword()
        {
            var model = new ResetPasswordViewModel();
            return View(model);
        }
        /// <summary>
        /// 重设密码，验证保存在redis 里的验证码
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            string key = RESET_PWD + model.UserName;

            var randomCode = _distributedCache.GetString(key);

            if (randomCode == null)
            {
                ModelState.AddModelError("ValidationCode", "验证码已过期");
            }
            else if (randomCode != model.ValidationCode)
            {
                ModelState.AddModelError("ValidationCode", "验证码错误");
            }
            else
            {
                var user = await _userManager.FindByNameAsync(model.UserName);
                if (user == null)
                {
                    // Don't reveal that the user does not exist
                    return RedirectToAction(nameof(ResetPasswordConfirmation));
                }
                var code = await _userManager.GeneratePasswordResetTokenAsync(user);
                var result = await _userManager.ResetPasswordAsync(user, code, model.Password);
                if (result.Succeeded)
                {
                    return RedirectToAction(nameof(ResetPasswordConfirmation));
                }
                AddErrors(result);
            }
            return View(model);
        }

        /// <summary>
        /// 展示密码重设成功界面
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public IActionResult ResetPasswordConfirmation()
        {
            return View();
        }


        [HttpGet]
        public IActionResult AccessDenied()
        {
            return View();
        }

        #region Helpers

        private void AddErrors(IdentityResult result)
        {
            ViewData["Error"] = "";
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
                ViewData["Error"] += error.Description;
            }
        }

        private IActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction(nameof(HomeController.Index), "Home",new { area = "" });
            }
        }

        #endregion
    }
}
